package server

import (
	"errors"
	"fmt"
	"linproxy/acl"

	"log"
	"net"
	"sync"
	"sync/atomic"
	"time"

	"github.com/sirupsen/logrus"
)

// Server 对外暴露的通用接口
type Server interface {
	Start() error
	Stop()
}

// ProxyServer 负责监听 + ACL 判定 + 调用业务处理逻辑
// 代理服务器
type ProxyServer struct {
	Vsysid   int
	Port     int
	Ip       string
	Protocol string

	listener   net.Listener
	packetConn net.PacketConn
	running    atomic.Bool
	quit       chan struct{}
	wg         sync.WaitGroup
}

// New 构造一个 ProxyServer
// 构造函数
func New(vsysID int, ip string, port int, protocol string) *ProxyServer {
	return &ProxyServer{
		Vsysid:   vsysID,
		Ip:       ip,
		Port:     port,
		Protocol: protocol,
		// ACL:      acl.New(whitelist),
	}
}

// Start 启动监听
func (s *ProxyServer) Start() error {
	//判断服务器是否已经正在进行
	if s.running.Load() {
		return errors.New("already running")
	}
	//检查协议是否正确
	proto, ok := normalizeProtocol(s.Protocol)
	if !ok {
		return fmt.Errorf("unsupported protocol: %s", s.Protocol)
	}
	s.Protocol = proto
	s.quit = make(chan struct{})
	addr := s.addr()

	switch proto {
	case "tcp": //TCP监听
		ln, err := net.Listen("tcp", addr) //获取主监听器
		if err != nil {
			return err
		}
		s.listener = ln
		s.wg.Add(1)
		go s.acceptLoop()
	case "udp":
		pc, err := net.ListenPacket("udp", addr)
		if err != nil {
			return err
		}
		s.packetConn = pc
		s.wg.Add(1)
		go s.udpLoop()
	}
	s.running.Store(true)
	log.Printf("[SERVER] %s listening on %s", s.Protocol, addr)
	return nil
}

// Stop 停止服务
func (s *ProxyServer) Stop() {
	if !s.running.Load() {
		return
	}
	close(s.quit)
	if s.listener != nil {
		_ = s.listener.Close()
	}
	if s.packetConn != nil {
		_ = s.packetConn.Close()
	}
	s.running.Store(false)
	s.wg.Wait()
	log.Println("[SERVER] stopped")
}

func (s *ProxyServer) addr() string { return fmt.Sprintf("%s:%d", s.Ip, s.Port) }

// // evalACL 判定是否允许访问
// func (s *ProxyServer) evalACL(ip string) bool {
// 	if s.ACL == nil {
// 		return true
// 	}
// 	ok, _ := s.ACL.Allow(ip)
// 	return ok
// }

func (s *ProxyServer) acceptLoop() {
	defer s.wg.Done()
	//使用通用接口获取白名单 -p--------------------------------------------
	whitelist := acl.GetWhiteList()
	for _, ip := range whitelist {
		logrus.Info("白名单ip:", ip)
	}
	//实例化白名单管理对象
	acl := acl.NewACL(whitelist)
	//死循环
	for {

		//阻塞等待客户端连接
		conn, err := s.listener.Accept() //获取client的连接 conn
		if err != nil {
			select {
			case <-s.quit:
				return
			default:
			}
			log.Printf("[SERVER] accept err: %v", err)
			continue
		}
		//根据连接句柄获取-->提取ip地址
		ip := extractIP(conn.RemoteAddr())
		//判断ip是否在白名单中
		if ok := acl.Allow(ip); !ok { //归属于ACL模块模块
			log.Printf("[TCP %s] rejected by ACL", ip)
			_ = conn.Close()
			continue
		}
		//ok的逻辑
		log.Printf("[TCP %s] accepted", ip)
		s.wg.Add(1)
		go func(c net.Conn) {
			defer s.wg.Done()
			HandleConnection(c)
		}(conn)
	}
}

func (s *ProxyServer) udpLoop() {
	defer s.wg.Done()
	buf := make([]byte, 64*1024)
	for {
		_ = s.packetConn.SetReadDeadline(time.Now().Add(5 * time.Second))
		n, addr, err := s.packetConn.ReadFrom(buf)
		if err != nil {
			if ne, ok := err.(net.Error); ok && ne.Timeout() {
				select {
				case <-s.quit:
					return
				default:
					continue
				}
			}
			select {
			case <-s.quit:
				return
			default:
			}
			log.Printf("[SERVER] udp read err: %v", err)
			continue
		}
		ip := extractIP(addr)
		//使用通用接口获取白名单
		whitelist := acl.GetWhiteList()
		//实例化白名单管理对象
		acl := acl.NewACL(whitelist)
		//判断ip是否在白名单中
		if ok := acl.Allow(ip); !ok {

			continue
		}
		data := make([]byte, n)
		copy(data, buf[:n])
		s.wg.Add(1)
		go func(d []byte, a net.Addr) { defer s.wg.Done(); HandleUDPPacket(s.packetConn, a, d) }(data, addr)
	}
}

// extractIP 从 net.Addr 中提取纯 IP 字符串
func extractIP(addr net.Addr) string {
	switch a := addr.(type) {
	case *net.TCPAddr:
		return a.IP.String()
	case *net.UDPAddr:
		return a.IP.String()
	default:
		if h, _, err := net.SplitHostPort(addr.String()); err == nil {
			return h
		}
		return addr.String()
	}
}
